package com.snowcattle.game.common.util;

import com.snowcattle.game.common.constant.CommonErrorLogInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;

/**
 * Http请求工具
 */
public class HttpUtil {

    private static final Logger logger = LoggerFactory.getLogger("HttpUtil");

    private static final int DEFAULT_TIMEOUT = 5;

    private static final String CHARSET = "charset=";
    /**
     * 连接超时,默认5秒
     */
    private static final int DEFAULT_CONNECT_TIMEOUT = 5000;
    /**
     * 读取超时,默认5秒
     */
    private static final int DEFAULT_READ_TIMEOUT = 5000;
    /**
     * 连接local的参数编码
     */
    private static final String DEFAULT_ENCODE_TYPE = "utf-8";

    private static final String EMPTY = "";


    private HttpUtil() {
    }

    private static HttpClient httpClient = null;

    static {
        httpClient = HttpClient.newBuilder().
                version(HttpClient.Version.HTTP_1_1).
                connectTimeout(Duration.ofMillis(5000)).build();
    }


    /**
     * 按照utf-8的编码格式进行编码
     *
     * @param param
     * @return
     */
    public static String encode(String param) {
        try {
            return URLEncoder.encode(param, DEFAULT_ENCODE_TYPE);
        } catch (IOException e) {
            if (logger.isErrorEnabled()) {
                logger.error(
                        ErrorsUtil.error(CommonErrorLogInfo.ARG_INVALID, "#Core.HttpUtil.encode",
                                String.format("String:%s endcode to type:%s exception", param, DEFAULT_ENCODE_TYPE)), e);
            }

            // 出异常了返回自身
            return param;
        }
    }

    public static String decode(String param, String defaultVal) {
        try {
            return URLDecoder.decode(param, DEFAULT_ENCODE_TYPE);
        } catch (IOException e) {
            if (logger.isErrorEnabled()) {
                logger.error(
                        ErrorsUtil.error(CommonErrorLogInfo.ARG_INVALID, "#Core.HttpUtil.decode",
                                String.format("String:%s decode to type:%s exception", param, DEFAULT_ENCODE_TYPE)), e);
            }

            // 出异常了返回给的默认值
            return defaultVal;
        }
    }


    /**
     * 对url的参数进行编码，并返回编码后的url
     *
     * @param requestParmUrl 带参数的url请求
     * @param params         ulr中的参数
     * @return
     */
    public static String encodeUrl(String requestParmUrl, Object... params) {
        // 对所有的字符类型参数进行编码
        for (int i = 0; i < params.length; i++) {
            Object _o = params[i];
            if (_o != null && _o instanceof String) {
                params[i] = encode((String) params[i]);
            }
        }
        return String.format(requestParmUrl, params);
    }

    /**
     * 带参数的url请求, 会先对URL中的参数进行编码
     *
     * @param requestParmUrl 请求的url
     * @param params         请求的参数
     * @return 返回的结果
     * @throws IOException
     */
    public static String getUrl(String requestParmUrl, Object... params) throws IOException {
        String _url = encodeUrl(requestParmUrl, params);
        return getUrl(_url);
    }

    /**
     * 尝试解析Http请求的编码格式,如果没有解析到则使用GBK编码(主要考虑到Local平台的返回编码是gb2312的)
     *
     * @param urlConnection
     * @return
     */
    static String parseEncoding(HttpURLConnection urlConnection) {
        String _encoding = urlConnection.getContentEncoding();
        if (_encoding != null) {
            return _encoding;
        }
        String _contentType = urlConnection.getContentType();
        if (_contentType != null) {
            int _index = _contentType.toLowerCase().indexOf(CHARSET);
            if (_index > 0) {
                _encoding = _contentType.substring(_index + CHARSET.length());
            }
        }
        if (_encoding != null) {
            return _encoding;
        } else {
            return DEFAULT_ENCODE_TYPE;
        }
    }

    public static String httpGetString(String url) {
        try {
            HttpRequest httpRequest = HttpRequest.newBuilder().GET().uri(URI.create(url)).build();
            HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
            return response.body();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return EMPTY;
    }

    public static String httpAsyncGetString(String url) {
        try {
            HttpRequest httpRequest = HttpRequest.newBuilder().GET().uri(URI.create(url)).build();
            CompletableFuture<String> response = httpClient.sendAsync(httpRequest,
                    HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body);
            return response.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return EMPTY;
    }

    public static String httpPostAsString(String url, String requestBody) {
        try {
            HttpRequest httpRequest = HttpRequest.newBuilder().
                    POST(HttpRequest.BodyPublishers.ofString(requestBody)).
                    header("Content-Type", "application/json").uri(URI.create(url)).build();
            HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
            return response.body();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return EMPTY;
    }

    public static String httpAsyncPostAsString(String url, String requestBody) {
        try {
            HttpRequest httpRequest = HttpRequest.newBuilder().
                    POST(HttpRequest.BodyPublishers.ofString(requestBody)).
                    header("Content-Type", "application/json").uri(URI.create(url)).build();
            CompletableFuture<String> response = httpClient.sendAsync(httpRequest,
                    HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body);
            return response.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return EMPTY;
    }

    public static String safelyDecodeHeader(String encodedHeaderValue) {
        if (StringUtils.isEmpty(encodedHeaderValue)) return EMPTY;
        if (!encodedHeaderValue.startsWith("%"))
            return encodedHeaderValue;
        try {
            return URLDecoder.decode(encodedHeaderValue, StandardCharsets.UTF_8);
        } catch (Exception e) {
        }
        return EMPTY;
    }

}
